﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Handin2_Del3
{
    /// <summary>
    /// A joint for connections out.
    /// 
    /// Only holds point coordinates.
    /// </summary>
    public class Joint
    {
        // Members and properties
        private Point pInnerPoint;
        public Point InnerPoint 
        {
            get { return pInnerPoint; }
            set { pInnerPoint = value; }
        }
        
        private Point pOuterPoint;
        public Point OuterPoint 
        {
            get { return pOuterPoint; }
            set { pOuterPoint = value; }
        }
        
        // Constructor
        public Joint(Point _pInnerPoint, Point _pOuterPoint)
        {
            pInnerPoint = _pInnerPoint;
            pOuterPoint = _pOuterPoint;
        }
    }
    
    /// <summary>
    /// Togglebutton with joints.
    /// </summary>
    public class Switch : ToggleButton
    {
        // Members and properties
        private Joint jA;
        public Joint JointA {
            get { return jA; }
            set { jA = value; }
        }
        
        private Joint jB;
        public Joint JointB {
            get { return jB; }
            set { jB = value; }
        }
        
        private Joint jC;
        public Joint JointC {
            get { return jC; }
            set { jC = value; }
        }
        
        // Constructor
        public Switch()
        {
            JointA = new Joint(new Point(0,0), new Point(0,0));
            JointB = new Joint(new Point(0,0), new Point(0,0));
            JointC = new Joint(new Point(0,0), new Point(0,0));
            moveJoints();
        }
        
        // Helper functions
        /// <summary>
        /// Move joints so they are placed accordingly to current position.
        /// </summary>
        public void moveJoints()
        {
            // Joint A: Left
            JointA.InnerPoint = new Point(Canvas.GetLeft(this) + 35,
                                                    Canvas.GetTop(this) + 80);
            JointA.OuterPoint = new Point(Canvas.GetLeft(this) + 35,
                                                    Canvas.GetTop(this) + 90);
            
            // Joint B: Right
            JointB.InnerPoint = new Point(Canvas.GetLeft(this) + 72,
                                                    Canvas.GetTop(this) + 80);
            JointB.OuterPoint = new Point(Canvas.GetLeft(this) + 72,
                                                    Canvas.GetTop(this) + 100);
            
            // Joint C: Top
            JointC.InnerPoint = new Point(Canvas.GetLeft(this) + this.Width/2 - 12,
                                                    Canvas.GetTop(this));
            JointC.OuterPoint = new Point(Canvas.GetLeft(this) + this.Width/2  - 12,
                                                    Canvas.GetTop(this) - 15);
        }
    }
    
    /// <summary>
    /// Image with joints.
    /// </summary>
    public class Bulb : Image
    {
        // Members and properties
        private Joint jA;
        public Joint JointA {
            get { return jA; }
            set { jA = value; }
        }
        
        private Joint jB;
        public Joint JointB {
            get { return jB; }
            set { jB = value; }
        }
        
        // Constructor
        public Bulb()
        {
            JointA = new Joint(new Point(0,0), new Point(0,0));
            JointB = new Joint(new Point(0,0), new Point(0,0));
            moveJoints();
        }
        
        // Helper functions
        /// <summary>
        /// Movejoints so they are placed accordingly to current position.
        /// </summary>
        public void moveJoints()
        {
            // Joint A: Left
            JointA.InnerPoint = new Point(Canvas.GetLeft(this) + 63,
                                                    Canvas.GetTop(this) + 95);
            JointA.OuterPoint = new Point(Canvas.GetLeft(this) + 63,
                                                    Canvas.GetTop(this) + 105);
            
            // Joint B: Right
            JointB.InnerPoint = new Point(Canvas.GetLeft(this) + 72,
                                                    Canvas.GetTop(this) + 95);
            JointB.OuterPoint = new Point(Canvas.GetLeft(this) + 72,
                                                    Canvas.GetTop(this) + 105);
        }
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // Members
        private double xOffset;
        private double yOffset;
        private ToggleButton tempButton;
        private List<Polyline> lstWires;
        private Joint jPlus;
        private Joint jMinus;

        public MainWindow()
        {
            InitializeComponent();
            
            // Init
            // :Wires
            lstWires = new List<Polyline>();
            
            // :Points
            jPlus = new Joint(new Point(0, 125), new Point(20, 125));
            jMinus = new Joint(new Point(0, 150), new Point(20, 150));
            
            // :Joints
            switch1.moveJoints();
            switch2.moveJoints();
            LightBulb.moveJoints();
            drawWires();
        }

        private void mainCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            
            // Element movement
            // -Element to move
            tempButton = (ToggleButton)sender;

            // -Element offset
            xOffset = Mouse.GetPosition(tempButton).X;
            yOffset = Mouse.GetPosition(tempButton).Y;
        }
        
        private void drawWires()
        {
            // Members
            SolidColorBrush scbBrushBlack = new SolidColorBrush(Colors.Black);
            SolidColorBrush scbBrushRed = new SolidColorBrush(Colors.Red);
            int iStrokeThickness = 2;
            
            // Wires and joints
            if(lstWires.Count > 0)
            {
                for(int i = 0; i < lstWires.Count; i++)
                    mainCanvas.Children.Remove(lstWires[i]);
            }
            switch1.moveJoints();
            switch2.moveJoints();
            lstWires.Clear(); // Clear old values
            
            // :Make lines
            Polyline p1A2B = connectJoints(switch1.JointA, switch2.JointB);
            Polyline p1B2A = connectJoints(switch1.JointB, switch2.JointA);
            Polyline pM1A = connectJoints(jMinus, switch1.JointC);
            Polyline pPLA = connectJoints(jPlus, LightBulb.JointA);
            Polyline pLB2C = connectJoints(LightBulb.JointB, switch2.JointC);
            
            // :Line settings
            p1A2B.Stroke = scbBrushBlack;
            p1A2B.StrokeThickness = iStrokeThickness;
            p1B2A.Stroke = scbBrushBlack;
            p1B2A.StrokeThickness = iStrokeThickness;
            pM1A.Stroke = scbBrushBlack;
            pM1A.StrokeThickness = iStrokeThickness;
            pPLA.Stroke = scbBrushBlack;
            pPLA.StrokeThickness = iStrokeThickness;
            pLB2C.Stroke = scbBrushBlack;
            pLB2C.StrokeThickness = iStrokeThickness;
            
            // :Coloring
            if(switch1.IsChecked == true && switch2.IsChecked == false)
            {
                p1A2B.Stroke = scbBrushRed;
                pPLA.Stroke = scbBrushRed;
                pM1A.Stroke = scbBrushRed;
                pLB2C.Stroke = scbBrushRed;
            }
            if(switch1.IsChecked == false && switch2.IsChecked == true)
            {
                p1B2A.Stroke = scbBrushRed;
                pPLA.Stroke = scbBrushRed;
                pM1A.Stroke = scbBrushRed;
                pLB2C.Stroke = scbBrushRed;
            }
            
            // :Add to list of wires
            lstWires.Add(p1A2B);
            lstWires.Add(p1B2A);
            lstWires.Add(pM1A);
            lstWires.Add(pPLA);
            lstWires.Add(pLB2C);
            
            // :Draw
            for(int i = 0; i < lstWires.Count; i++)
                mainCanvas.Children.Add(lstWires[i]);
        }

        private void moveElement()
        {
            // Move element
            if (tempButton != null)
            {
                Canvas.SetLeft(tempButton, Mouse.GetPosition(mainCanvas).X - xOffset);
                Canvas.SetTop(tempButton, Mouse.GetPosition(mainCanvas).Y - yOffset);
            }
        }

        private void mainCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            moveElement();
            drawWires();
        }

        private void mainCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            tempButton = null;
        }

        /// <summary>
        /// Returns a line between 2 joints.
        /// </summary>
        /// <param name="_jOne"></param>
        /// <param name="_jTwo"></param>
        /// <returns></returns>
        public static Polyline connectJoints(Joint _jOne, Joint _jTwo)
        {
            Point p1 = new Point();
            Point p2 = new Point();
            Polyline poly = new Polyline();
            
            // Joint
            poly.Points.Add(_jOne.InnerPoint);
            poly.Points.Add(_jOne.OuterPoint);
            
            // Connection
            // :Lazy
            if(_jOne.OuterPoint.Y > _jTwo.OuterPoint.Y)
            {
                if(_jOne.OuterPoint.X < _jTwo.OuterPoint.X)
                    p1 = new Point(_jTwo.OuterPoint.X, _jOne.OuterPoint.Y);
                else if(_jOne.OuterPoint.X > _jTwo.OuterPoint.X)
                    p1 = new Point(_jTwo.OuterPoint.X, _jOne.OuterPoint.Y);
                else
                    p1 = _jOne.OuterPoint;
            }
            else if(_jOne.OuterPoint.Y < _jTwo.OuterPoint.Y)
            {
                if(_jOne.OuterPoint.X < _jTwo.OuterPoint.X)
                    p1 = new Point(_jOne.OuterPoint.X, _jTwo.OuterPoint.Y);
                else if(_jOne.OuterPoint.X > _jTwo.OuterPoint.X)
                    p1 = new Point(_jOne.OuterPoint.X, _jTwo.OuterPoint.Y);
                else
                    p1 = _jOne.OuterPoint;
            }
            else
                p1 = _jOne.OuterPoint;
            poly.Points.Add(p1);
            
            // Joint
            poly.Points.Add(_jTwo.OuterPoint);
            poly.Points.Add(_jTwo.InnerPoint);
            return(poly);
        }
    }
}
